package references

import (
	"jvm/nzpJvm/instructions/base"
	"jvm/nzpJvm/runtime_area"
	"jvm/nzpJvm/runtime_area/heap"
)

// 用于调用父类方法，私有方法，构造方法
type INVOKE_SPECIAL struct{ base.Index16Instruction }

func (self *INVOKE_SPECIAL) Execute(frame *runtime_area.Frame) {
	currentClass := frame.Method().Class()
	constantPool := currentClass.ConstantPool()
	methodRef := constantPool.GetConstant(self.Index).(*heap.MethodRef)
	// 此方法引用的所引用的方法所属的类
	class := methodRef.ResolveClass()
	// 此方法引用所引用的方法
	method := methodRef.ResolveMethod()
	// 构造方法只允许用来构造方法所属的类的实例
	if method.Name() == "<init>" && method.Class() != class {
		panic("java.lang.NoSuchMethodError")
	}
	// 这个指令不能用来调用静态方法
	if method.IsStatic() {
		panic("java.lang.IncompatibleClassChangeError")
	}
	// 要调用这个方法的实例
	object := frame.OperandStack().GetRefFromTop(method.ArgsSlotCount())
	if object == nil {
		panic("java.lang.NullPointerException")
	}

	// 检查是否有权限访问
	if !base.CheckMethodAccess(method, object, currentClass) {
		panic("java.lang.IllegalAccessError")
	}
	methodToBeInvoke := method
	// 如果调用的是超类中的非构造方法，需要从超类中查找对应的方法。对应的java代码就是super.aMethod（）
	if currentClass.IsSuper() && currentClass.IsSubClassOf(class) && method.Name() != "<init>"{
		methodToBeInvoke = heap.LookupMethodInClass(currentClass.SuperClass(),methodRef.Name(),methodRef.Descriptor())
	}
	if methodToBeInvoke == nil ||methodToBeInvoke.IsAbstract() {
		panic("java.lang.AbstractMethodError")
	}
	base.InvokeMethod(frame,methodToBeInvoke)

}
